﻿using HYQuick;
using HYQuickUI;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Windows.Forms.Integration;

namespace HYQuick
{
    internal class HYQuickListener
    {
        [DllImport("user32.dll")]
        public static extern IntPtr GetForegroundWindow();//获得当前前台窗体句柄；句柄是用来标识对象或项目的标识符
        [DllImport("User32.dll", CharSet = CharSet.Auto)]
        public static extern int GetWindowThreadProcessId(IntPtr hwnd, out int ID);//找出某个窗口的创建者（线程或进程），返回创建者的标识符

        public static HYQuickListener Listener
        {
            get
            {
                return s_listener ?? (s_listener = new HYQuickListener());//？？表示合并运算符
            }
        }

        private HYQuickListener()
        {
            m_notify = Program.notify; //暂时还不知道
            m_HYQuickHotkey = new Hotkey(IntPtr.Zero);   //将句柄设置为零;
            m_contextHotkey = new Hotkey(IntPtr.Zero); //将句柄设置为零;

            Init();
        }

        public void Init()//初始化
        {
            //配置部分
            HYQuickConfig.ThisConfig.Reload();
            HYQuickConfig.ThisConfig.CurrentVersion = Application.ProductVersion;//Application:获取指示调用方能否退出该应用程序的值(bool) productversion:返回产品的版本
            HYQuickConfig.ThisConfig.TrySave();

            m_HYQuickModels = new Dictionary<string, HYQuickModel>();//了解HYQuickModel的意思

            var globalModel = HYQuickModel.GetModel(HYQuickModel.GlobalModelName + ".xml");
            m_HYQuickModels.Add(HYQuickModel.GlobalModelName, globalModel);    //添加全局Model

            foreach (var item in HYQuickConfig.ThisConfig.ModelName)
            {
                if (!m_HYQuickModels.ContainsKey(item))
                {
                    m_HYQuickModels.Add(item, HYQuickModel.GetModel(item + ".xml"));
                }
            }

            //装载插件
            HYQuickPluginLoader.AddAdditionQuickMethodTo(m_HYQuickModels);

            m_HYQuickContextWindowHandler = new HYQuickContextWindowHandler();
            m_HYQuickContextWindow = new HYQuickContextWindow(m_HYQuickContextWindowHandler);
            ElementHost.EnableModelessKeyboardInterop(m_HYQuickContextWindow);
        }

        public void Run()
        {
            m_HYQuickHotkey.RegisterHotkey(HYQuickConfig.ThisConfig.HYQuickHotKey, (Hotkey.KeyFlags)HYQuickConfig.ThisConfig.HYQuickHotKeyFlags);
            m_HYQuickHotkey.OnHotkey += HYQuickHotkey_OnHotkey;

            m_contextHotkey.RegisterHotkey(HYQuickConfig.ThisConfig.ContextMenuHotKey, (Hotkey.KeyFlags)HYQuickConfig.ThisConfig.ContextMenuHotKeyFlags);
            m_contextHotkey.OnHotkey += ContextHotkey_OnHotkey;
        }

        public void Reload()
        {
            m_HYQuickHotkey.UnregisterHotkeys();
            m_contextHotkey.UnregisterHotkeys();
            m_HYQuickHotkey = new Hotkey(IntPtr.Zero);
            m_contextHotkey = new Hotkey(IntPtr.Zero);
            Init();
            Run();
        }

        private void ContextHotkey_OnHotkey(int HotKeyID)
        {
            try
            {
                object obj = GetActiveObject(false);
                if (HYQuickConfig.ThisConfig.ContextMenuToogle)
                {
                    var textObject = HYQuickReflection.Invoke(m_currentModel.Search, obj);
                    if (textObject != null)
                    {
                        m_HYQuickContextWindow.Show(textObject.ToString());
                        HYQuickVitality.UpdateVitality("context", m_currentModel.ProgramName, textObject.ToString());
                    }
                }
            }
            catch { }
        }

        public void HYQuickHotkey_OnHotkey(int HotKeyID)
        {
            Trigger(false);
        }

        private void Trigger(bool forceGetGlobalObject)
        {
            HYQuickContext HYQuickContext = default(HYQuickContext);
            bool isGlobal;
            Process currentProcess;
            IntPtr windowPtr;
            object obj = GetActiveObject(forceGetGlobalObject, out isGlobal, out windowPtr, out currentProcess);
            SetupHYQuickMainWindowAndHandler(obj, HYQuickContext, windowPtr, isGlobal, currentProcess);
            TriggerHYQuickMainWindow(isGlobal);
        }

        private void TriggerHYQuickMainWindow(bool isGlobal)
        {
            if (m_HYQuickMainWindow != null && m_HYQuickMainWindow.IsVisible)
            {
                m_HYQuickMainWindow.Close(); //如果窗体已存在并在显示状态，则触发FormClosing，Hide()
                if (!isGlobal)
                {
                    // 非公共窗口，再次触发快捷键会打开Global的window
                    Trigger(true);
                }
                return;
            }
            else
            {
                if (m_currentModel.MethodList.Count > 0)
                {
                    HYQuickVitality.UpdateVitality("showlist", m_currentModel.ProgramName, "");
                    m_HYQuickMainWindow.Show();
                    m_HYQuickMainWindow.Activate();
                }
            }
        }

        private object GetGlobalObject(IntPtr windowPtr, bool isGlobal)
        {
            if (m_commonObject == null)
                m_commonObject = new HYQuickCommonObject(windowPtr, isGlobal); //调用公共的Model
            return m_commonObject;
        }

        private object GetActiveObject(bool bForceGetGlobalObject)
        {
            bool isGlobal;
            Process currentProcess;
            IntPtr windowPtr;
            return GetActiveObject(false, out isGlobal, out windowPtr, out currentProcess);
        }

        private object GetActiveObject(bool bForceGetGlobalObject, out bool isGlobalModel, out IntPtr windowPtr, out Process currentProcess)
        {
            object currentActiveObject = null;
            windowPtr = GetForegroundWindow();
            int currentPID;
            GetWindowThreadProcessId(windowPtr, out currentPID);
            currentProcess = Process.GetProcessById(currentPID);    //获得活动窗口的进程

            isGlobalModel = true;
            string modelProcessName = string.Empty;
            if (bForceGetGlobalObject || !m_HYQuickModels.ContainsKey(currentProcess.ProcessName, true, out modelProcessName))
            {
                modelProcessName = HYQuickModel.GlobalModelName;
            }

            if (!isGlobalModel)
                Validate(currentProcess.ProcessName);
            m_currentModel = m_HYQuickModels[modelProcessName];

            if (m_currentModel.ProgramName.Trim() != "")
            {
                bool bFailed = true;
                foreach (var name in m_currentModel.ProgramName.Split(','))
                {
                    try
                    {
                        currentActiveObject = Marshal.GetActiveObject(name.Trim()); //调用当前的Model
                        bFailed = false;
                        break;
                    }
                    catch { }
                }

                if (!bFailed)
                {
                    isGlobalModel = false;
                }
                else
                {
                    m_currentModel = m_HYQuickModels[HYQuickModel.GlobalModelName];
                    currentActiveObject = GetGlobalObject(windowPtr, true); //调用公共的Model
                }
            }
            else
            {
                currentActiveObject = GetGlobalObject(windowPtr, true); //调用公共的Model
            }

            return currentActiveObject;
        }

        private void SetupHYQuickMainWindowAndHandler(object obj, HYQuickContext HYQuickContext, IntPtr windowPtr, bool isGlobal, Process currentProcess)
        {
            if (m_handlerMap == null)
                m_handlerMap = new Dictionary<HYQuickModel, HYQuickMainWindowHandler>();
            if (m_windowMap == null)
                m_windowMap = new Dictionary<HYQuickMainWindowHandler, HYQuickMainWindow>();

            HYQuickMainWindowHandler handler = null;
            if (m_handlerMap.ContainsKey(m_currentModel))
            {
                handler = m_handlerMap[m_currentModel];
            }
            else
            {
                handler = new HYQuickMainWindowHandler(obj, m_currentModel, HYQuickContext, windowPtr, isGlobal, currentProcess);
                m_handlerMap.Add(m_currentModel, handler);
            }

            if (m_windowMap.ContainsKey(handler))
            {
                m_HYQuickMainWindow = m_windowMap[handler];
            }
            else
            {
                m_HYQuickMainWindow = new HYQuickMainWindow(handler);
                ElementHost.EnableModelessKeyboardInterop(m_HYQuickMainWindow);
                m_windowMap.Add(handler, m_HYQuickMainWindow);
            }

            System.Windows.Media.Color bgColor = System.Windows.Media.Color.FromRgb((byte)m_currentModel.BorderColorR, (byte)m_currentModel.BorderColorG, (byte)m_currentModel.BorderColorB);
            m_HYQuickMainWindow.SetBackgroundColor(bgColor);
        }

        private void Validate(String processName)
        {
            Process[] processes = Process.GetProcessesByName(processName);
            if (processes.Length > 1)
            {
                m_notify.ShowBalloonTip("您开启了多个" + processName + "进程，当您调用快捷菜单时，只能对第一个进程进行操作，如果要对其他" + processName + "进行操作，请关闭多余的此类进程。");
            }
        }

        private static HYQuickListener s_listener;
        private Dictionary<String, HYQuickModel> m_HYQuickModels;
        private Hotkey m_HYQuickHotkey;
        private Hotkey m_contextHotkey;
        private HYQuickContextWindow m_HYQuickContextWindow;
        private HYQuickContextWindowHandler m_HYQuickContextWindowHandler;
        private HYQuickModel m_currentModel;
        private HYQuickMainWindow m_HYQuickMainWindow;
        private NotifyIcon m_notify;
        private HYQuickCommonObject m_commonObject;
        private Dictionary<HYQuickModel, HYQuickMainWindowHandler> m_handlerMap;
        private Dictionary<HYQuickMainWindowHandler, HYQuickMainWindow> m_windowMap;
    }
}
